﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Principal;

namespace NFramework
{
    public class FrameworkContext : IPrincipal, IDisposable
    {
        protected FrameworkContext() { }

        #region [ Current ]

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods")]
        public static FrameworkContext Current
        {
            get{ return GetCurrent<FrameworkContext>(); }
        }

        protected static T GetCurrent<T>() where T : FrameworkContext
        {
            FrameworkContext current = System.Threading.Thread.CurrentPrincipal as FrameworkContext;
            if (current == null) {
                System.Threading.Thread.CurrentPrincipal = new FrameworkContext();
            }
            return System.Threading.Thread.CurrentPrincipal as T;
        }

        protected static T Push<T>(T context) where T : FrameworkContext
        {
            context._previous = Current;
            System.Threading.Thread.CurrentPrincipal = context;
            return context;
        }
        private FrameworkContext _previous;

        public static void Pop()
        {
            FrameworkContext previous = Current._previous;
            if (previous != null)
            {
                System.Threading.Thread.CurrentPrincipal = previous;
            }
        }

        public static void Pop(int count)
        {
            FrameworkContext previous = Current;
            while (count > 0)
            {
                if (previous._previous == null) { break; }
                previous = previous._previous;
                count--;
            }
            System.Threading.Thread.CurrentPrincipal = previous;
        }

        public static void PopAll()
        {
            FrameworkContext previous = Current;
            while (previous._previous != null)
            {
                previous = previous._previous;
            }
            System.Threading.Thread.CurrentPrincipal = previous;
        }

        #endregion

        #region [ IPrincipal Members ]

        public virtual IIdentity Identity
        {
            get { return new System.Security.Principal.GenericIdentity("Unknown"); }
        }

        public virtual bool IsInRole(string role)
        {
            return false;
        }

        #endregion

        #region [ IDisposable Members ]

        public void Dispose()
        {
            if (FrameworkContext.ReferenceEquals(Current, this)) {
                Pop();
            } else {
                RemoveFromStack(this, Current);
            }
        }

        private static void RemoveFromStack(FrameworkContext toRemove, FrameworkContext currentStackPosition)
        {
            if (FrameworkContext.ReferenceEquals(currentStackPosition._previous, toRemove)) {
                    currentStackPosition._previous = toRemove._previous;
            } else if (currentStackPosition._previous != null) {
                RemoveFromStack(toRemove, currentStackPosition._previous);
            }
        }

        #endregion
    }
}
